from abc import abstractmethod
from decimal import Decimal
from math import exp
import sys
import random
from ConstraintBasedLocalSearch import ConstraintBasedLocalSearch

def schedule(t, k=20, lam=0.005, limit=600):
    if t < limit:
    	return k * exp(-lam * t)
    return 0

class SimulatedAnneling(ConstraintBasedLocalSearch):

	def __init__(self):
		self.index = 2500 #need to test the right value
		self.localStateManager = None
	
	@abstractmethod
	def simulateAnneling(self, schedule=schedule):
		for t in xrange(sys.maxint):
			temp = schedule(t)
			if temp == 0.00 or self.localStateManager.evalutateState(self.localStateManager.currentState)==0:
				return (self.localStateManager.currentState, t+1, self.localStateManager.evalutateState(self.localStateManager.currentState))
			successors = self.localStateManager.generateSuccessors()
			minVal = sys.maxint
			next = successors[0]
			for s in successors:
				val = self.localStateManager.evalutateState(s)
				if val < minVal:
					next = s	
			diff = self.localStateManager.evalutateState(self.localStateManager.currentState) - self.localStateManager.evalutateState(next)
			if diff > 0:
				self.localStateManager.currentState = next
			else:
				prob = exp(diff/temp)
				n = random.random()		# [0.0, 1.0]
				if n <= prob:
					self.localStateManager.currentState = next
			#print "TEMP: " + str(temp) + "\tCONFLICTS: " + str(self.localStateManager.evalutateState(self.localStateManager.currentState))
		return (self.localStateManager.currentState, t+1, self.localStateManager.evalutateState(self.localStateManager.currentState)) 
		
	def initStateManager(self):
		self.localStateManager = LocalStateManager(None)
		self.localStateManager.generateInitState() 